import { Component, OnInit, ElementRef } from '@angular/core';
import { Action } from "@ngrx/store"
import { Subject } from "rxjs/Subject"
import { Observable } from "rxjs/Observable"
import { QuoteTableComponent } from "./../quote-table.component";
import { TableState } from "./../quote-table.service";

import { getHeightOfElem } from "./../utils";

export const GO_FIRST = "GO_FIRST",
  GO_NEXT = "GO_NEXT",
  GO_PRE = "GO_PRE",
  GO_LAST = "GO_LAST",
  GO_TO = "GO_TO",
  SET_PAGE_SIZE = "SET_PAGE_SIZE",
  SET_TOTAL = "SET_TOTAL";

interface PageState {
  currentPage: number;
  pageSize: number;
  lastPageIndex: number;
}

const getResult =
  (data: any[], state: PageState) => {
    // console.debug("GET RESULT: ", this);
    return data && data.length ?
      data.slice(state.currentPage * state.pageSize, (state.currentPage + 1) * state.pageSize) :
      [];
  }

const getMinAboveZero = num => Math.max(num, 0);

@Component({
  // moduleId: module.id,
  selector: 'quote-pagination',
  templateUrl: 'quote-pagination.component.html',
  styleUrls: [
    "quote-pagination.component.less"
  ],
  inputs: [
    "tableInstance",
    "quoteState",
    "pageSize",
    "subject",
    "updateEventSource"
  ]
})
export class QuotePaginationComponent implements OnInit {
  subject: Subject<any>;
  quoteState: Observable<TableState>;
  store;
  pageIndexs;
  pageState;
  pageSize;
  tempState;
  updateEventSource;
  tableInstance: QuoteTableComponent;
  rowHeight: number;
  headerRowHeight: number;

  /**
   * Creates an instance of QuotePaginationComponent.
   * 建立仓库对象
   * 
   * @memberOf QuotePaginationComponent
   */
  constructor(private elem: ElementRef) {
    this.store = new Subject().scan((state, action: Action) => {
      switch (action.type) {
        case GO_NEXT:
          return Object.assign({}, state, {
            currentPage: state.currentPage < state.lastPageIndex - 1 ? state.currentPage + 1 : state.currentPage
          });
        case GO_PRE:
          return Object.assign({}, state, {
            currentPage: state.currentPage > 0 ? state.currentPage - 1 : state.currentPage
          });
        case GO_FIRST:
          return Object.assign({}, state, {
            currentPage: 0
          });
        case GO_LAST:
          return Object.assign({}, state, {
            currentPage: state.lastPageIndex
          });
        case GO_TO:
          return Object.assign({}, state, {
            currentPage: action.payload.index
          });
        case SET_PAGE_SIZE:
          return Object.assign({}, state, {
            pageSize: action.payload.pageSize,
            lastPageIndex: Math.ceil(state.total / action.payload.pageSize),
            currentPage: getMinAboveZero(Math.min(state.currentPage, Math.ceil(state.total / action.payload.pageSize) - 1))
          });
        case SET_TOTAL:
          return Object.assign({}, state, {
            total: action.payload.total,
            lastPageIndex: Math.ceil(action.payload.total / state.pageSize),
            // currentPage: Math.min(state.currentPage, Math.ceil(action.payload.total / state.pageSize) - 1)
          });
        default: return state;
      }
    }, {
        total: 0,
        currentPage: 0,
        pageSize: 8,
        lastPageIndex: 10
      }
    ).publishReplay()
    this.store.connect()
  }

  ngOnInit() {
    let { quoteState, subject, store, updateEventSource } = this;
    //表格数据服务整理出排数据后，暂存于本实例，并更新仓库状态
    quoteState.subscribe(result => {
      this.tempState = result;
      this.updatePageSize();
      // console.debug("QUOTE STATE UPDATE: ", result);
      store.next({
        type: SET_TOTAL,
        payload: {
          total: result["length"]
        }
      });
    });
    //仓库状态更新后，讲筛选后结果传出
    store.subscribe(pageState => subject.next(getResult(this.tempState, pageState)));
    //仓库状态更新后，更新页码状态
    store.subscribe(pageState => this.updateIndex(pageState));

    //若有强制更新源，则强制更新时回到首页
    if (updateEventSource) {
      updateEventSource.subscribe((params) => {
        this.goPage(0);
      })
    }

  }

  goPre() {
    this.store.next({
      type: GO_PRE
    });
  }

  goNext() {
    this.store.next({
      type: GO_NEXT
    });
  }

  goPage(index: number) {
    this.store.next({
      type: GO_TO,
      payload: {
        index
      }
    });
  }

  getPageSize() {
    // 待调整
    let { tableSet, options } = this.tableInstance;
    // let tableHeight = getHeightOfElem(this.elem.nativeElement.parentElement.getElementsByClassName("quote-table")[0]);
    let tableTop = this.elem.nativeElement.parentElement.getElementsByClassName("quote-table-main")[0].getBoundingClientRect().top;
    let pageTop = this.elem.nativeElement.getBoundingClientRect().top;
    // console.debug("Height: ", tableTop, pageTop);
    // let tableHeight = getHeightOfElem(tableSet.nativeElement);
    // let validHeight = withHeaders ? tableHeight - rowHeight : tableHeight;
    let validHeight = Math.abs(tableTop - pageTop);
    // console.debug("validHeight: ", validHeight, options.responsive.rowHeight, Math.floor(validHeight / options.responsive.rowHeight))
    return Math.floor(validHeight / options.responsive.rowHeight);
  }

  /**
   * 待优化
   * 
   * 
   * @memberOf QuotePaginationComponent
   */
  updatePageSize() {
    // console.debug("PageSize: ", this.getPageSize());
    this.store.next({
      type: SET_PAGE_SIZE,
      payload: {
        pageSize: this.getPageSize()
      }
    });
  }

  updateIndex(pageState: PageState) {
    if (!Number.isFinite(pageState.lastPageIndex)) return;
    // console.debug("UPDATE INDEX: ", pageState);
    this.pageState = pageState;
    this.pageIndexs =
      new Array(pageState.lastPageIndex)
        .fill(1)
        .map((v, i) => i)
        .filter(i => Math.abs(i) < 2 || Math.abs(i - pageState.lastPageIndex) < 2 || Math.abs(i - pageState.currentPage) < 2)
        .map((v, i, a) => {
          if (Math.abs(v - a[i - 1]) > 1) {
            return [-1, v];
          }
          return v;
        })
        .reduce((newArr: any[], v) => {
          if (Array.isArray(v)) {
            return [...newArr, ...v];
          } else {
            return [...newArr, v];
          }
        }, [])
  }

}